﻿/*
 * framemodbusrtu.hpp
 *
 *  Created on: 2017年3月1日
 *      Author: work
 */

#ifndef _DM_PROTOCOL_FRAMEMODBUSRTU_HPP_
#define _DM_PROTOCOL_FRAMEMODBUSRTU_HPP_

#include <dm/export.hpp>

#ifndef DM_API_PROTOCOL
#define DM_API_PROTOCOL DM_API_IMPORT
#endif

#include <dm/protocol/frame.hpp>
#include <dm/types.hpp>

namespace dm{
namespace protocol{

class DM_API_PROTOCOL CFrameModbusRtu:public CFrame{
public:
	typedef dm::uint8 address_t;

	enum{
		MaxBufLen = 255,

		Address_All = 0	// 广播地址
	};

	enum EFunc{
		UnknowFunc = 0x00,
		ReadCoilStatus  = 0x01,
		ReadInputStatus = 0x02,
		ReadHoldReg     = 0x03,
		ReadInputReg    = 0x04,
		ForceSigCoil    = 0x05,
		PresetSigReg    = 0x06,
		ReadExcptStatus = 0x07,
		FetchEventCount = 0x0B,
		FetchEventLog   = 0x0C,
		ForceMtlCoil    = 0x0F,
		PresetMtlReg    = 0x10,
		ReportSlaveId   = 0x11,
		ReadGeneralRef  = 0x14,
		WriteGeneralRef = 0x15,
		MaskWrite4XReg  = 0x16,
		ReadWrite4XReg  = 0x17,
		ReadFifoQueue   = 0x18
	};

	enum EErrCode{
		Err_None = 0x00,
		Err_Func  = 0x01,
		Err_Addr  = 0x02,
		Err_Value = 0x03,
		Err_Slave = 0x04,
		Err_Ack   = 0x05,
		Err_Busy  = 0x06,
		Err_Nack  = 0x07,
		Err_Memo  = 0x08
	};

	enum EDir{
		Dn = 0,
		Up
	};

	CFrameModbusRtu();
	CFrameModbusRtu( const CFrameModbusRtu& frame );
	virtual ~CFrameModbusRtu(){}

	CFrameModbusRtu& operator=( const CFrameModbusRtu& frame );

	inline const address_t& getAddress()const{
		return m_address;
	}

	inline void setAddress( const address_t& addr ){
		m_address = addr;
	}

	inline const EDir& getDir()const{
		return m_dir;
	}

	inline void setDir( const EDir& dir ){
		m_dir = dir;
	}

	inline void setDirUp(){
		setDir(Up);
	}

	inline void setDirDn(){
		setDir(Dn);
	}

	inline bool isDirUp()const{
		return m_dir==Up;
	}

	inline bool isDirDn()const{
		return m_dir==Dn;
	}

	EFunc getFunc()const;
	void setFunc( const EFunc& func );

	bool isUpError()const;
	void setUpError( const bool& e = true );

	inline const dm::uint8& getDataLen()const{
		return m_len;
	}

	bool setDataLen( const dm::uint8& len );

	inline const dm::uint8* getData()const{
		return m_data;
	}

	bool setData( const dm::uint8* buf,const dm::uint8& len,const dm::uint8& p=0 );
	bool setData( const dm::uint8& p,const dm::uint8& d );

	bool encode( txbuf_t& buf )const;
	bool decode( const rxbuf_t& buf,const pos_t& end,pos_t& start,const CFrame* txFrame );

	bool setDnReadCmd( dm::uint16 addr, dm::uint16 size );

	/////////////////////////////////////////////
	void setReadCoils( const dm::uint16& startAddress,const dm::uint16& quantity );
	void setReadDiscreteInputs( const dm::uint16& startAddress,const dm::uint16& quantity );
	void setReadHoldingRegisters( const dm::uint16& startAddress,const dm::uint16& quantity );
	void setReadInputRegisters( const dm::uint16& startAddress,const dm::uint16& quantity );
	void setWriteSingleCoil( const dm::uint16& address,const bool& on );
	void setWriteSingleRegister( const dm::uint16& address,const dm::uint16& value );
	void setWriteMultipleCoils( const dm::uint16& startAddress,const dm::uint16& quantity,const dm::uint8* output );

	void setWriteMultipleRegisters( const dm::uint16& startAddress,const dm::uint16& quantity,const dm::uint16* output );
	void setWriteMultipleRegisters( const dm::uint16& startAddress,const dm::uint16& quantity );
	void setWriteMultipleRegistersDataUint16( int offset,dm::uint16 d );
	void setWriteMultipleRegistersDataInt16( int offset,dm::int16 d );

	/////////////////////////////////////////////

	void setDataAndLen( const dm::uint16& startAddress,const dm::uint16& quantity );
	void setDataZero();

	static dm::uint8 getDataLenByBits( const dm::uint16& quantity );
	void setDataByBits( const dm::uint8& pos,const dm::uint8& offset,const dm::uint8& b );
	dm::uint8 getDataAsBit( const dm::uint8& pos,const dm::uint8& offset )const;

	void setDataByUint16( const dm::uint8& pos,const dm::uint8& offset,const dm::uint16& r );
	dm::uint16 getDataAsUint16( const dm::uint8& pos,const dm::uint8& offset )const;

protected:
	void setData( const rxbuf_t& buf,const pos_t& start,const dm::uint8& len );
	void crcCalc( const dm::uint8* buf,const int& size,dm::uint8* sum )const;
	bool crcCheck( const rxbuf_t& buf,const pos_t& start,const int& size,const dm::uint8* sum )const;
protected:
	EDir m_dir;

	address_t m_address;
	dm::uint8 m_func;
	dm::uint8 m_data[MaxBufLen];
	dm::uint8 m_len;
};

}
}



#endif /* INCLUDE_DM_PROTOCOL_FRAMEMODBUSRTU_HPP_ */
